Class Objects

Python is what is known as an object-oriented programming language. This means python allows a programmer to define special custom data structures called classes that not only can contain their own data elements, but special fucntions called methods that can potentially alter a class instance's internal state.

Classes are defined through the keyword class, followed by the name of the class, which, by convention, is capitalized. This is followed by a code block that specifies the methods that define a class. Note that classes are a rich and complex topic in python. However, much of the functionality a data scientist may wish to use, in particular, python's machine learning libraries, will be accessed through class objects. Please see the official documentation for more info.


In [1]:
# defining a class
class TestClass:
    def im_a_class(self):
        print "hi! i'm a class!"

    def hello(self, name):
        print "hello %s!" % name

Note that the method functions inside the class definition take a special extra parameter, self. This tells the method that it is assigned to an example of a class, and when it is invoked, it potentially operates on that example, but not other examples of that class.

Concrete examples of classes are called class objects. These are created using a special function called a class constructor. In python, unless the programmer specifies otherwise, all classes are assigned a class constructor that doesn't take any arguments, and doesn't do anything beyond create a new example class object. These constructor functions are invoked by calling the class name as if you were calling a function, that is, using the class name with parentheses afterwards.

Methods associated with a class can be invoked by the special dot operator (.). Here, you take a class object, a concrete example of a class, often assigned to a variable, then use the dot character (.), then the method you wish to call. This method operates only on the class object to the left of the dot. The arguments passed to these methods ignore the special self, keyword mentioned above, you only need to pass in what is to the right of this keyword, if anything.


In [2]:
a_test_class = TestClass()
a_test_class.im_a_class()


a_test_class.hello("josh")


hi! i'm a class!
hello josh!

As mentioned above, classes always have a special function called a constructor that is used to build concrete instances of class objects. A programmer can define their own constructor function, defining any actions that are performed when building a new class object, and data that are used internally within a class object. Like all functions, constructors can take arguments that can be used during their execution. Like methods in a class, the constructor definition takes the special self parameter as the left most argument in it's definition. This allows you to modify the internal state of the class object being constructed. Here is an example class with a custom constructor. Note that internal variables or methods can be accessed through the dot operator on self.


In [3]:
class Person:
    
    def __init__(self, first_name, last_name):
        # this constructor sets the values of "member variables"
        # in the concrete class object being constructed
        self.first = first_name
        self.last = last_name
        self.hollers = 0

    def holler(self):
        # modifying an internal example
        self.hollers = self.hollers + 1
        print "%s has been hollered at %d times" % (self.first, self.hollers)
        
josh = Person("josh", "attenberg")
josh.holler()
josh.holler()
# accessing the value of a member variable
print josh.first


josh has been hollered at 1 times
josh has been hollered at 2 times
josh

List Comprehensions

The practical data scientist often faces situations where one list is to be transformed into another list, transforming the values in the input array, filtering out certain undesired values, etc. List comprehensions are a natural, flexible way to perform these transformations on the elements in a list.

The syntax of list comprehensions is based on the way mathematicians define sets and lists, a syntax that leaves it clear what the contents should be:

  • S = {x² : x in {0 ... 9}}

  • V = (1, 2, 4, 8, ..., 2¹²)

  • M = {x | x in S and x even}

Python's list comprehensions give a very natural way to write statements just like these. You can write math-like expressions without having to much special syntax.


In [5]:
import math
S = [math.pow(x, 2) for x in range(0,10)]
V = [math.pow(2, x) for x in range(0, 13)]
M = [x for x in S if x%2 == 0]

print S
print V
print M


[0.0, 1.0, 4.0, 9.0, 16.0, 25.0, 36.0, 49.0, 64.0, 81.0]
[1.0, 2.0, 4.0, 8.0, 16.0, 32.0, 64.0, 128.0, 256.0, 512.0, 1024.0, 2048.0, 4096.0]
[0.0, 4.0, 16.0, 36.0, 64.0]

Note the list comprehension for deriving M uses a "if statement" to filter out those values that aren't of interest, restricting to only the even perfect squares.

These are simple examples, using numerical compuation. In the following operation we transform a string into an list of values, a more complex operation:


In [6]:
words = 'The quick brown fox jumps over the lazy dog'
[[w.upper(), w.lower(), len(w)] for w in words.split()]


Out[6]:
[['THE', 'the', 3],
 ['QUICK', 'quick', 5],
 ['BROWN', 'brown', 5],
 ['FOX', 'fox', 3],
 ['JUMPS', 'jumps', 5],
 ['OVER', 'over', 4],
 ['THE', 'the', 3],
 ['LAZY', 'lazy', 4],
 ['DOG', 'dog', 3]]